//CoreLocalInterruptor.scala
package mycore

import chisel3._
import chisel3.util._

class CoreLocalInterruptor extends Module{
  val io = IO(new Bundle{
	
  val Valid = Input(Bool())

	val ClintLoad = Flipped(new DataLoad)
  val ClintStore = Flipped(new DataStore)

  val DataLoad = new DataLoad
  val DataStore = new DataStore

  val TimeOver = Output(Bool())
  val ClintValid = Output(Bool())
  
  })

  //simple decode
  val Addr  = Mux(io.ClintLoad.en, io.ClintLoad.addr(31,0), 0.U) | Mux(io.ClintStore.en, io.ClintStore.addr(31,0), 0.U)
  val wdata = io.ClintStore.data
  val hit_mtime 	= Addr === "h0200bff8".U
  val hit_mtimecmp 	= Addr === "h02004000".U

  //Clint valid
  val ren = io.ClintLoad.en  && (hit_mtimecmp || hit_mtime) && io.Valid
  val wen = io.ClintStore.en && (hit_mtimecmp || hit_mtime) && io.Valid
  val ClintValid = ren || wen

  //the number of cycles required to increment the mtime register by 1
  val tickCnt = RegInit(1.U(128.W))
  val tick = tickCnt === 5.U
  when(tick){
  	tickCnt := 1.U
  }.otherwise{
  	tickCnt := tickCnt + 1.U
  }

  val mtime    = RegInit(0.U(64.W))
  val mtimecmp = RegInit(0.U(64.W))

  when(wen && hit_mtime) {
  	mtime := wdata 
  }.otherwise { 
  	mtime := mtime + tick.asUInt
  }

  when(wen && hit_mtimecmp) { mtimecmp := wdata }

  val temp_mtime 	= Mux(ren && hit_mtime,    mtime, 	 0.U)
  val temp_mtimecmp = Mux(ren && hit_mtimecmp, mtimecmp, 0.U)
  val rdata = temp_mtime | temp_mtimecmp

  //pass DataLoad
  io.DataLoad.en 	:= Mux(ClintValid, false.B,   io.ClintLoad.en)
  io.DataLoad.addr 	:= io.ClintLoad.addr
  io.DataLoad.size  := io.ClintLoad.size
  io.ClintLoad.data := Mux(ClintValid, rdata, 	io.DataLoad.data)

  //pass DataStore
  io.DataStore.en 	:= Mux(ClintValid, false.B, io.ClintStore.en)
  io.DataStore.addr := io.ClintStore.addr
  io.DataStore.data := io.ClintStore.data
  io.DataStore.mask := io.ClintStore.mask

  io.TimeOver := mtime >= mtimecmp
  io.ClintValid := ClintValid

}